/** Interface class, part of the Gallion Fight Game Project
 * Copyright (2010 - 2011) Nicolas Brunie 
 **/
// including external libraries
#include "Material.hpp"
#include <iostream>
#include <cstdlib>
#include "math.h"
#include <glm/glm.hpp>
#include <glm/gtc/matrix_projection.hpp>
#include <glm/gtc/matrix_transform.hpp>

// including internal headers
#include "Shader.h"
#include "utils.hpp"
#include "GL/glext.h"
#include "Screen.hpp"
#include "Object.hpp"
#include "FontManager.hpp"

#ifndef __INTERFACE_HPP__
#define __INTERFACE_HPP__ 

using namespace std;
using namespace glm;

enum buttonState {
	mouseOver, mouseOut, active
};






/** Virtual class for all interface element */
class InterfaceElement {
	public:
		/** generic function called by Interface Class instance to render the element
		 */
		virtual void render() = 0;
};

/** Virtual class for all updatable interface element */
class UpdatableElement {
	public:
		/** generic function called by Interface Class instance to update element */
		virtual void update(float) = 0;
};

class ActionListener {
	public:
		/** function called by Element to trigger an action, args can be used
		  * for passing any type of pre-known argument */ 
		virtual void receiveAction(string type, void* args) = 0;
};

/** Virtual class for elements which can interact with mouse */
class MouseMoveSensibleElement {
	protected:
		/** position of the left-down corner of the element*/
		vec2 position;

		/** dimensions of the element*/
		float m_width, m_height;

	public:
		/** function to test intersection between mouse click and element
		 * param[in] x floating-point X of mouse
		 * param[in] y floating-point  Y of mouse
		*/
		virtual bool intersect(float x, float y) {
			if (x > position.x and x < position.x + m_width and
				y > position.y and y < position.y + m_height) return true;
			return false;
		};

		/** function to call when Mouse is over the element */
		virtual void mouseOver() = 0;

		/** function to call when Mouse is not over the element */
		virtual void mouseOut() = 0;
};


class KeyListener {
	public:
		/** function to send a key to this key listener */
		virtual bool getKey(int) = 0;

		/** function to send a command to this KeyListener */
		virtual bool getCommand(int) = 0;

		/** function to validate text (typing "Return") */
		virtual bool validateText() = 0;
};

/** class button for all elements clickacble and with an interaction */
class Button {
	protected:
		/** coords button into the screen */
		vec2 m_buttonCoords;

		/** button dimensions (dx,dy) */
		vec2 m_dimensions;

		/** pointer to an action listener, the button will register 
		  * this action listener, and send its commands to it */
		ActionListener* m_actionListener;

		list<Button*>::iterator m_buttonIterator;
	public:
		///** function for rendering button into interface*/
		//virtual void render() = 0;

		/** function to manage mouse click, return true if click is 
		  * on the button, false elsewhere */
		virtual void action() = 0;

		/** function for detecing whether or not a click is made
		  * on the button return true if true for warning that this mouse click
		  * has been managed by this element (avoiding one click on multiple element) */
        virtual bool manageMouseClick(float x, float y) {                             
            if ((x >= m_buttonCoords.x) && (x <= m_buttonCoords.x + m_dimensions.x) &&            
                (y >= m_buttonCoords.y) && (y <= m_buttonCoords.y + m_dimensions.y)) {            
				action();
                return true;
            };
            return false;                                                             
        };

		/** setting button iterator in button list (will be used when deleted) */
		void setButtonIterator(list<Button*>::iterator it_) { m_buttonIterator = it_;};

		/** retrieve button iterator */
		list<Button*>::iterator getButtonIterator() { return m_buttonIterator;};


		/**  register the binded action listener */
		void setActionListener(ActionListener* act_) { m_actionListener = act_;};


		/** setting click zone dimensions */
		void setDimensions(vec2 dx_dy) { m_dimensions = dx_dy;};
};

class InterfaceImage : public InterfaceElement {
	private:
		/** openGL integer identifier to image texture */
		GLuint m_textureId;
	
		/** image width*/
		float width;
		/** image height */
		float height;

		/** image depth : layer of rendering (more this float is low, more image will be in front of that one) */
		float m_depth;

		/** image coords */
		float x,y;

		/** vertex array for quad rendering image */
		GLfloat* vertexArray;
	public:
		list<InterfaceImage*>::iterator m_iterator;

		/** constructor : build vertex array and retrieve texture identifier */
		InterfaceImage(string name, float width_, float height_, float depth_);

		/** setting image dimension */
		void setWidth(float w) { width = w;};

		/** defining image position on screen */
		void setPosition(float x_, float y_) { x = x_; y = y_;};

		/** rendering image on screen */
		virtual void render();

		/** rendering image on screen with translation, without considering
		  * (x,y) coords of InteraceImage  */
		void render(float tx, float ty);
};


class VirtualWindow {
	protected:
		/** windows coordinates (x,y) */
		glm::vec2 m_coords;


		/** iterator to this window pointer in interface list */
		list<VirtualWindow*>::iterator m_iterator;

		/** when this flag is set to false, window has to be destroyer by interface.
		  * Has to be initialized to true during window creation  */
		bool m_openFlag;
	public:
		/** this function could be overloaded for executing same operation
		  * when the Virtual window is destroyed (child class in a VIrtualWindow list) */
		virtual void onDestroy() { };

		/** rendering function, has to be overloaded by child class */
		virtual void render() = 0;

		virtual bool update(float time) { return m_openFlag;};

		/** retrieving window iterator in Interface list */
		list<VirtualWindow*>::iterator getIterator() { return m_iterator;};

		/** setting window iterator */
		void setIterator(list<VirtualWindow*>::iterator it_) { m_iterator = it_;};
};

class SelectionListener {
	public:
		 // function called at each selection
		virtual void setActive(Object*) = 0;
};




class VirtualInterface {
	protected:
		Object* m_selected;
		list<SelectionListener*> m_selectionListenerList;
		FontExporter* m_fontExporter;
		KeyListener* m_keyListener;
	public:
		//virtual void addInterfaceImage(InterfaceImage*) = 0;
		virtual void addWindow(VirtualWindow*) = 0;
		virtual void registerSelectionListener(SelectionListener* sl_) { m_selectionListenerList.push_back(sl_);};
		void setSelected(Object* selected_) { 
			m_selected = selected_; 
			list<SelectionListener*>::iterator it = m_selectionListenerList.begin();
			for (; it != m_selectionListenerList.end(); it++) { (*it)->setActive(selected_);};
		};
		void drawString(float x, float y, string s) {
			m_fontExporter->drawString(x,y,s);
		};
		void registerKeyListener(KeyListener* kl) { m_keyListener = kl;};
		void unregisterKeyListener() { m_keyListener = NULL;};
		bool receiveKey(int key) { 
			if (key == 13) return false;
			if (m_keyListener) return m_keyListener->getKey(key); 
			return false;
		};

		/** this function is generally called by an event gestionner when it a key is pressed,
		 *		by default, the key is sent to the registered key listener, if it deals with the 
		 *		key himself, true is returned and the event gestionner does take the key into account 
		 *		else false is returned, thus the event gestionned considers that the key was not
		 * 		destinated to the interface and deals with it on its own */
		bool receiveCommand(int key) {
			if (m_keyListener) return m_keyListener->getCommand(key);
			return false;
		};
};




#endif
